1
'*************************** Module Header ******************************'
2 ' Module Name: FTPClientManager.vb
4 ' Copyright (c) Microsoft Corporation.
6 ' The class FTPClientManager supplies following features:
7 ' 1. Verify whether a file or a directory exists on the FTP server.
8 ' 2. Delete files or directories on the FTP server.
9 ' 3. Create a directory on the FTP server.
10 ' 4. Manage the FTPUploadClient to upload files to the FTP server.
13 ' This source is subject to the Microsoft Public License.
14 ' See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
15 ' All other rights reserved.
17 ' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
18 ' EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
19 ' WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
20 '*************************************************************************'
26 Partial
Public Class FTPClientManager
29 ''' The Credentials to connect to the FTP server.
31 Public Property Credentials() As ICredentials
34 ''' The current URL of this FTPClient.
37 Public Property Url() As Uri
41 Private Set(ByVal value
As Uri
)
46 Private _status
As FTPClientManagerStatus
49 ''' Get or Set the status of this FTPClient.
51 Public Property Status() As FTPClientManagerStatus
56 Private Set(ByVal value
As FTPClientManagerStatus
)
57 If _status
<> value
Then
60 ' Raise a OnStatusChanged event.
61 Me.OnStatusChanged(EventArgs
.Empty
)
67 Public Event UrlChanged
As EventHandler
69 Public Event ErrorOccurred
As EventHandler(Of ErrorEventArgs
)
71 Public Event StatusChanged
As EventHandler
73 Public Event FileUploadCompleted
As EventHandler(Of FileUploadCompletedEventArgs
)
75 Public Event NewMessageArrived
As EventHandler(Of NewMessageEventArg
)
78 ''' Initialize a FTPClient instance.
80 Public Sub New(ByVal url
As Uri
, ByVal credentials
As ICredentials
)
81 Me.Credentials
= credentials
83 ' Check whether the Url exists and the credentials is correct.
84 ' If there is an error, an exception will be thrown.
90 Me.Status
= FTPClientManagerStatus
.Idle
95 ''' Navigate to the parent folder.
97 Public Sub NavigateParent()
98 If Url
.AbsolutePath
<> "/" Then
100 ' Get the parent url.
101 Dim newUrl
As New Uri(Me.Url
, "..")
103 ' Check whether the Url exists.
104 CheckFTPUrlExist(newUrl
)
107 Me.OnUrlChanged(EventArgs
.Empty
)
114 Public Sub Naviagte(ByVal newUrl
As Uri
)
115 ' Check whether the Url exists.
116 Dim urlExist
As Boolean = VerifyFTPUrlExist(newUrl
)
119 Me.OnUrlChanged(EventArgs
.Empty
)
123 ''' If the Url does not exist, an exception will be thrown.
125 Private Sub CheckFTPUrlExist(ByVal url
As Uri
)
126 Dim urlExist
As Boolean = VerifyFTPUrlExist(url
)
129 Throw
New ApplicationException("The url does not exist")
134 ''' Verify whether the url exists.
136 Private Function VerifyFTPUrlExist(ByVal url
As Uri
) As Boolean
137 Dim urlExist
As Boolean = False
140 urlExist
= VerifyFileExist(url
)
142 urlExist
= VerifyDirectoryExist(url
)
149 ''' Verify whether the directory exists.
151 Private Function VerifyDirectoryExist(ByVal url
As Uri
) As Boolean
152 Dim request
As FtpWebRequest
= TryCast(WebRequest
.Create(url
), FtpWebRequest
)
153 request
.Credentials
= Me.Credentials
154 request
.Method
= WebRequestMethods
.Ftp
.ListDirectory
156 Dim response
As FtpWebResponse
= Nothing
159 response
= TryCast(request
.GetResponse(), FtpWebResponse
)
161 Return response
.StatusCode
= FtpStatusCode
.DataAlreadyOpen
162 Catch webEx
As System
.Net
.WebException
163 Dim ftpResponse
As FtpWebResponse
= TryCast(webEx
.Response
, FtpWebResponse
)
165 If ftpResponse
.StatusCode
= FtpStatusCode
.ActionNotTakenFileUnavailable
Then
171 If response IsNot
Nothing Then
178 ''' Verify whether the file exists.
180 Private Function VerifyFileExist(ByVal url
As Uri
) As Boolean
181 Dim request
As FtpWebRequest
= TryCast(WebRequest
.Create(url
), FtpWebRequest
)
182 request
.Credentials
= Me.Credentials
183 request
.Method
= WebRequestMethods
.Ftp
.GetFileSize
185 Dim response
As FtpWebResponse
= Nothing
188 response
= TryCast(request
.GetResponse(), FtpWebResponse
)
190 Return response
.StatusCode
= FtpStatusCode
.FileStatus
191 Catch webEx
As System
.Net
.WebException
192 Dim ftpResponse
As FtpWebResponse
= TryCast(webEx
.Response
, FtpWebResponse
)
194 If ftpResponse
.StatusCode
= FtpStatusCode
.ActionNotTakenFileUnavailable
Then
200 If response IsNot
Nothing Then
207 ''' Get the sub directories and files of the current Url by default.
209 Public Function GetSubDirectoriesAndFiles() As IEnumerable(Of FTPFileSystem
)
210 Return GetSubDirectoriesAndFiles(Me.Url
)
214 ''' Get the sub directories and files of the Url. It will be used in enumerate
216 ''' When run the FTP LIST protocol method to get a detailed listing of the files
217 ''' on an FTP server, the server will response many records of information. Each
218 ''' record represents a file.
220 Public Function GetSubDirectoriesAndFiles(ByVal url
As Uri
) _
221 As IEnumerable(Of FTPFileSystem
)
222 Dim request
As FtpWebRequest
= TryCast(WebRequest
.Create(url
), FtpWebRequest
)
223 request
.Credentials
= Me.Credentials
224 request
.Method
= WebRequestMethods
.Ftp
.ListDirectoryDetails
226 Dim response
As FtpWebResponse
= Nothing
227 Dim responseStream
As Stream
= Nothing
228 Dim reader
As StreamReader
= Nothing
230 response
= TryCast(request
.GetResponse(), FtpWebResponse
)
232 Me.OnNewMessageArrived(New NewMessageEventArg _
233 With {.NewMessage
= response
.StatusDescription
})
235 responseStream
= response
.GetResponseStream()
236 reader
= New StreamReader(responseStream
)
238 Dim subDirs
As New List(Of FTPFileSystem
)()
240 Dim subDir
As String = reader
.ReadLine()
242 ' Find out the FTP Directory Listing Style from the recordString.
243 Dim style
As FTPDirectoryListingStyle
= FTPDirectoryListingStyle
.MSDOS
244 If Not String.IsNullOrEmpty(subDir
) Then
245 style
= FTPFileSystem
.GetDirectoryListingStyle(subDir
)
247 Do While Not String.IsNullOrEmpty(subDir
)
248 subDirs
.Add(FTPFileSystem
.ParseRecordString(url
, subDir
, style
))
250 subDir
= reader
.ReadLine()
254 If response IsNot
Nothing Then
258 ' Close the StreamReader object and the underlying stream, and release
259 ' any system resources associated with the reader.
260 If reader IsNot
Nothing Then
267 ''' Create a sub directory of a folder on the remote FTP server.
269 Public Sub CreateDirectoryOnFTPServer(ByVal serverPath
As Uri
,
270 ByVal subDirectoryName
As String)
272 ' Create the Url for the new sub directory.
273 Dim subDirUrl
As New Uri(serverPath
, subDirectoryName
)
275 ' Check whether sub directory exist.
276 Dim urlExist
As Boolean = VerifyFTPUrlExist(subDirUrl
)
283 ' Create an FtpWebRequest to create the sub directory.
284 Dim request
As FtpWebRequest
= TryCast(WebRequest
.Create(subDirUrl
),
286 request
.Credentials
= Me.Credentials
287 request
.Method
= WebRequestMethods
.Ftp
.MakeDirectory
289 Using response
As FtpWebResponse
= TryCast(request
.GetResponse(),
291 Me.OnNewMessageArrived(New NewMessageEventArg _
292 With {.NewMessage
= response
.StatusDescription
})
295 ' If the folder does not exist, create the folder.
296 Catch webEx
As System
.Net
.WebException
298 Dim ftpResponse
As FtpWebResponse
= TryCast(webEx
.Response
, FtpWebResponse
)
300 Dim msg
As String = String.Format(
301 "There is an error while creating folder {0}. " _
302 & " StatusCode: {1} StatusDescription: {2} ",
303 subDirUrl
.ToString(),
304 ftpResponse
.StatusCode
.ToString(),
305 ftpResponse
.StatusDescription
)
306 Dim errorException
As New ApplicationException(msg
, webEx
)
308 ' Fire the ErrorOccurred event with the error.
309 Dim e
As ErrorEventArgs
= New ErrorEventArgs _
310 With {.ErrorException
= errorException
}
312 Me.OnErrorOccurred(e
)
317 ''' Delete items on FTP server.
319 Public Sub DeleteItemsOnFTPServer(ByVal fileSystems
As IEnumerable(Of FTPFileSystem
))
320 If fileSystems Is
Nothing Then
321 Throw
New ArgumentException("The item to delete is null!")
324 For Each fileSystem
In fileSystems
325 DeleteItemOnFTPServer(fileSystem
)
331 ''' Delete an item on FTP server.
333 Public Sub DeleteItemOnFTPServer(ByVal fileSystem
As FTPFileSystem
)
334 ' Check whether sub directory exist.
335 Dim urlExist
As Boolean = VerifyFTPUrlExist(fileSystem
.Url
)
343 ' Non-Empty folder cannot be deleted.
344 If fileSystem
.IsDirectory
Then
345 Dim subFTPFiles
= GetSubDirectoriesAndFiles(fileSystem
.Url
)
347 DeleteItemsOnFTPServer(subFTPFiles
)
350 ' Create an FtpWebRequest to create the sub directory.
351 Dim request
As FtpWebRequest
= TryCast(WebRequest
.Create(fileSystem
.Url
),
353 request
.Credentials
= Me.Credentials
355 request
.Method
= If(fileSystem
.IsDirectory
,
356 WebRequestMethods
.Ftp
.RemoveDirectory,
357 WebRequestMethods
.Ftp
.DeleteFile
)
359 Using response
As FtpWebResponse
= TryCast(request
.GetResponse(),
361 Me.OnNewMessageArrived(New NewMessageEventArg _
362 With {.NewMessage
= response
.StatusDescription
})
364 Catch webEx
As System
.Net
.WebException
365 Dim ftpResponse
As FtpWebResponse
= TryCast(webEx
.Response
, FtpWebResponse
)
367 Dim msg
As String = String.Format(
368 "There is an error while deleting {0}. " _
369 & " StatusCode: {1} StatusDescription: {2} ",
370 fileSystem
.Url
.ToString(),
371 ftpResponse
.StatusCode
.ToString(),
372 ftpResponse
.StatusDescription
)
373 Dim errorException
As New ApplicationException(msg
, webEx
)
375 ' Fire the ErrorOccurred event with the error.
376 Dim e
As ErrorEventArgs
= New ErrorEventArgs _
377 With {.ErrorException
= errorException
}
379 Me.OnErrorOccurred(e
)
384 ''' Upload a whole local folder to FTP server.
386 Public Sub UploadFolder(ByVal localFolder
As DirectoryInfo
,
387 ByVal serverPath
As Uri
, ByVal createFolderOnServer
As Boolean)
388 ' The method UploadFoldersAndFiles will create or override a folder by default.
389 If createFolderOnServer
Then
390 UploadFoldersAndFiles(New FileSystemInfo() {localFolder
}, serverPath
)
392 ' Upload the files and sub directories of the local folder.
394 UploadFoldersAndFiles(localFolder
.GetFileSystemInfos(), serverPath
)
399 ''' Upload local folders and files to FTP server.
401 Public Sub UploadFoldersAndFiles(ByVal fileSystemInfos
As IEnumerable(Of FileSystemInfo
),
402 ByVal serverPath
As Uri
)
403 If Me._status
<> FTPClientManagerStatus
.Idle
Then
404 Throw
New ApplicationException("This client is busy now.")
407 Me.Status
= FTPClientManagerStatus
.Uploading
409 Dim uploadClient
As New FTPUploadClient(Me)
411 ' Register the events.
412 AddHandler uploadClient
.AllFilesUploadCompleted
,
413 AddressOf uploadClient_AllFilesUploadCompleted
414 AddHandler uploadClient
.FileUploadCompleted
,
415 AddressOf uploadClient_FileUploadCompleted
417 uploadClient
.UploadDirectoriesAndFiles(fileSystemInfos
, serverPath
)
421 Private Sub uploadClient_FileUploadCompleted(ByVal sender
As Object,
422 ByVal e
As FileUploadCompletedEventArgs
)
423 Me.OnFileUploadCompleted(e
)
426 Private Sub uploadClient_AllFilesUploadCompleted(ByVal sender
As Object,
427 ByVal e
As EventArgs
)
428 Me.Status
= FTPClientManagerStatus
.Idle
431 Protected Overridable
Sub OnUrlChanged(ByVal e
As EventArgs
)
432 RaiseEvent UrlChanged(Me, e
)
435 Protected Overridable
Sub OnStatusChanged(ByVal e
As EventArgs
)
436 RaiseEvent StatusChanged(Me, e
)
439 Protected Overridable
Sub OnFileUploadCompleted(ByVal e
As FileUploadCompletedEventArgs
)
440 RaiseEvent FileUploadCompleted(Me, e
)
443 Protected Overridable
Sub OnErrorOccurred(ByVal e
As ErrorEventArgs
)
444 Me.Status
= FTPClientManagerStatus
.Idle
446 RaiseEvent ErrorOccurred(Me, e
)
449 Protected Overridable
Sub OnNewMessageArrived(ByVal e
As NewMessageEventArg
)
450 RaiseEvent NewMessageArrived(Me, e
)